package com.itheima.health.security;


import com.alibaba.fastjson.JSON;
import com.itheima.health.entity.Result;
import com.itheima.health.exception.BusinessRuntimeException;
import com.itheima.health.pojo.Permission;
import com.itheima.health.pojo.Role;
import com.itheima.health.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.AntPathMatcher;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

@Slf4j
@WebFilter(urlPatterns = "/*") //过滤器拦截所有得后端路径
public class HealthSecurityFilter implements Filter {

    //创建一个String数组,存放不需要拦截得路径
    private String[] unLoginAccessUrlList = new String[]{
            "/user/login", //登录路径不拦
            "/user/logout", //退出路径不拦
            "/common/**",   //?
            "/mobile/**",// 移动端的无需登录都可以访问接口
    };
    //创建一个map集合,存放需要拦截校验得路径和访问对应资源需要得校验码
      //键为urr  值为 权限校验码
    private Map<String,String> loginAuthUrlMap= new HashMap<>();

    //自定义方法,存放需要进行权限校验的路径和其对应的校验码
    private void initAuthUrlMap(){
        //与删除有关的访问路径和校验码
        loginAuthUrlMap.put("/checkitem/delete","CHECKITEM_DELETE");
        loginAuthUrlMap.put("/checkgroup/delete","CHECKGROUP_DELETE");
        loginAuthUrlMap.put("/setmeal/delete","SETMEAL_DELETE");
        loginAuthUrlMap.put("/report/**","REPORT_VIEW");
    }

    //自定义方法-判断是否是不需要登录即可访问的路径
    private boolean isCheckUrl(String url){
        //创建路径匹配器对象
        AntPathMatcher antPathMatcher = new AntPathMatcher();
        //遍历放行的路径数组
        for (String u : unLoginAccessUrlList) {
          /*3:调用  径匹配对象的match("放行的路径","请求路径")进行判断
                true :表示请求路径是放行的路径
                false:不是放行路径
            */
          if(antPathMatcher.match(u,url)){
              return true;
          }
        }
        return false;
    }
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        //初始化过滤器时,加载需要进行校验的路径和验证码的Map集合
        initAuthUrlMap();
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        //对请求和响应对象进行向下转型
       HttpServletRequest req=(HttpServletRequest)request;
       HttpServletResponse res = (HttpServletResponse)response;
       //获取请求路径
        String requestURI = req.getRequestURI();
        log.info(requestURI+"被拦截器拦截了");
        //调用判断是否为放行路径的方法
        boolean checkUrl = isCheckUrl(requestURI);
        if(checkUrl){   //true是不需要登录就可以放行的路径
            log.info(requestURI+"是不需要登录即可放行资源");
            chain.doFilter(req,res); //放行
            return;
        }
        //访问不放行的路径,先判断是否登录过--通过会话中的数据
        User user =(User)req.getSession().getAttribute("user");
        if(user==null){//表示未登录--跳转到登录
            //前端没做重定向
            log.info("请重新登录");
            res.setContentType("application/json; charset=UTF-8");
         //   throw new BusinessRuntimeException("请先登录");
            res.getWriter().write(JSON.toJSONString(new Result(false,"请先登录")));
            return;
        }
                 //表示登录过了
        //判断路径是否需要权限校验--采用根据路径获取检验码
        String authKeyWork = loginAuthUrlMap.get(requestURI);
        if(authKeyWork==null){//说明访问的资源不需要权限校验--放行
            chain.doFilter(req,res);
            return;
        }
        //表示authKeyWork不为null,是需要验证用户权限才能放行的资源
        //根据用户id查询用户角色信息--会话中存放的是用户所有信息
        //遍历用户所有角色
        for (Role role : user.getRoles()) {
            //获取每个角色的拥有的权限
            Set<Permission> permissions = role.getPermissions();
            //对每个角色的权限进行遍历
            for (Permission permission : permissions) {
                //判断是否符合资源访问的权限
                if(permission.getKeyword().equals(authKeyWork)){//权限符合-放行
                    chain.doFilter(req,res);
                    return;
                }
            }
        }
        //没有此权限--提示
        log.info("没有操作权限");
        //解决前端乱编码问题
        res.setContentType("application/json; charset=UTF-8");
        res.getWriter().write(JSON.toJSONString(new Result(false,"没有操作权限")));
    }

    @Override
    public void destroy() {

    }
}
